﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.Threading;
using System.Collections.Concurrent;
using Cherry.Agile.Core.Instrumentation;
using Cherry.Agile.Core;

namespace Cherry.Agile.ServiceModel {
    /// <summary>
    /// 
    /// </summary>
    public sealed class ContextLifetimeManager : ChannelLifeTimeManager, IDisposable {
        string key = Guid.NewGuid().ToString();
        static ThreadLocal<Dictionary<string, object>> _clients = new ThreadLocal<Dictionary<string, object>>();
        public ContextLifetimeManager() {
            if (_clients.Value == null)
                _clients.Value = new Dictionary<string, object>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="newValue"></param>
        public override void SetValue(object newValue) {
            
            _clients.Value[key] = newValue as object;
        }

        public override void RemoveValue() {
            if (_clients.Value != null && _clients.Value != null) {
                base.RemoveValue(_clients.Value[key] as IClientChannel);
                _clients.Value.Remove(key);
            }
        }

        public override object GetValue() {
            if(_clients.Value.ContainsKey(key))
                return _clients.Value[key];
            return null;
        }

        public override void TearDown() {
            Clear();
        }

        public static void Clear() {
            if (_clients == null && _clients != null)
                return;
            var _dict = _clients.Value;
            foreach (var item in _clients.Value.Values) {
                ServiceFactory.CloseService(item as IDisposable);
            }
            _clients.Value = new Dictionary<string,object>();
        }
    }


    public class ChannelLifeTimeManager : LifetimeManager, IDisposable {
        private static readonly IClientInstrumentationProvider _instrumentation;
        static ThreadLocal<Dictionary<string, object>> _clients = new ThreadLocal<Dictionary<string, object>>();
        string key = Guid.NewGuid().ToString();

        static ChannelLifeTimeManager() {
            _instrumentation = Unity.GetClientInstrumentationProvider();
           
        }

        public ChannelLifeTimeManager() {
            if (_clients.Value == null)
                _clients.Value = new Dictionary<string, object>();
        }
               
        public override object GetValue() {
            if (_clients.Value != null && _clients.Value.ContainsKey(key))
                return _clients.Value[key];
            return null;
        }

        public override void RemoveValue() {
            RemoveValue(GetValue() as IClientChannel);
            if (_clients.Value != null)
                _clients.Value.Remove(key);
        }

        protected virtual void RemoveValue(IClientChannel val) {
            if (val != null) {
                try {
                    if (val.State == CommunicationState.Faulted) {
                        val.Abort();
                        if (_instrumentation != null)
                            _instrumentation.Faulted();
                    } else {
                        val.Close();
                        if (_instrumentation != null)
                            _instrumentation.Closed();
                    }
                } catch (ObjectDisposedException) {
                    
                }
               
            }
        }

        public override void SetValue(object newValue) {
            RemoveValue();
            if (_clients.Value != null) {
                _clients.Value[key] = newValue;
                if (newValue != null && !(newValue is IClientChannel))
                    return;// throw new ArgumentException("the value must be a wcf channel");
                if (_instrumentation != null)
                    _instrumentation.Created();
            }
        }

        public void Dispose() {
            RemoveValue();
        }

        public virtual void TearDown() {
            if (_clients == null)
                return;
            var _dict = _clients.Value;
            foreach (var item in _clients.Value.Values) {
                ServiceFactory.CloseService(item as IDisposable);
            }
            _clients.Value = new Dictionary<string,object>();
        }
    }
}
